package com.dsideal.cloud.cas.client.controller;

import com.dsideal.cloud.annotation.DsidealLog;
import com.dsideal.cloud.auth.common.util.jwt.IJWTInfo;
import com.dsideal.cloud.auth.core.config.UserAuthenticationConfig;
import com.dsideal.cloud.cas.client.constant.LoginConstants;
import com.dsideal.cloud.cas.client.dto.UserDetailsDTO;
import com.dsideal.cloud.cas.client.entity.RestLogin;
import com.dsideal.cloud.cas.client.entity.TokenEntity;
import com.dsideal.cloud.cas.client.entity.UserLog;
import com.dsideal.cloud.cas.client.manager.LoginManager;
import com.dsideal.cloud.cas.client.utils.JWTInfoForCas;
import com.dsideal.cloud.common.constant.BusinessType;
import com.dsideal.cloud.common.constant.ErrorCode;
import com.dsideal.cloud.common.entity.Roles;
import com.dsideal.cloud.common.response.BaseResponse;
import com.dsideal.cloud.common.response.ObjectRestResponse;
import com.dsideal.cloud.cas.client.cache.RedisUserCache;
import com.dsideal.cloud.cas.client.cas.constant.ServerConfig;
import com.dsideal.cloud.cas.client.cas.entity.CasUserDetails;
import com.dsideal.cloud.cas.client.cas.properties.CasConfiguration;
import com.dsideal.cloud.cas.client.cas.restful.CasRestfulService;
import com.dsideal.cloud.cas.client.config.MysqlConfig;
import com.dsideal.cloud.cas.client.constant.CasConstants;
import com.dsideal.cloud.cas.client.properties.RequestProperties;
import com.dsideal.cloud.cas.client.utils.JwtTokenUtil;
import com.dsideal.cloud.common.util.CheckParametersUtil;
import com.dsideal.cloud.common.util.DateUtils;
import com.dsideal.cloud.common.util.IpUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.security.cas.authentication.CasAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.Principal;
import java.util.*;

import static com.dsideal.cloud.cas.client.constant.CasConstants.SYSTEM_CODE_KEY;

/**
 *
 * @author suny
 */
@RestController
@Slf4j
public class MainController {

    @Autowired
    private TokenEntity tokenEntity;

    @Autowired
    private ServerConfig serverConfig;

    @Autowired
    private CasConfiguration casConfiguration;


    @Autowired
    private UserAuthenticationConfig userAuthenticationConfig;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private RedisUserCache redisUserCache;

    @Autowired
    private CasRestfulService restfulService;

    @Autowired
    private MysqlConfig mysqlConfig;

    @Autowired
    private RequestProperties properties;

    @Autowired
    private LoginManager loginManager;

    @Autowired
    private Environment env;

    /**
     * CAS Restful API 用户登录
     * @return
     */
    @PostMapping("/login/restful")
    @DsidealLog(title = "用户登录",businessType = BusinessType.LOGIN)
    public BaseResponse login(@RequestBody RestLogin userInfo) throws Exception {
        log.info(userInfo.getUsername()+"-------登录---------");
      String redirectUrl;
        CheckParametersUtil.getInstance().put(userInfo.getUsername(),CasConstants.USERNAME_KEY)
                .put(userInfo.getPassword(),CasConstants.PASSWORD_KEY)
                .put(userInfo.getCode(),CasConstants.SYSTEM_CODE_KEY).checkParameter();
        Map<String,String> params =new HashMap<>();
        params.put(CasConstants.USERNAME_KEY, userInfo.getUsername());
        params.put(CasConstants.PASSWORD_KEY, userInfo.getPassword());
        params.put(CasConstants.SYSTEM_CODE_KEY, userInfo.getCode());

            /**
             * 通过CAS Restful API方式进行登录认证
             */
            redirectUrl = restfulService.authenticate(params);

        String token="";
        if(StringUtils.isNotBlank(redirectUrl)){
            UserDetailsDTO userDetailsDTO = loginManager.extendUserInfo(params.get(CasConstants.USERNAME_KEY));
            if(userDetailsDTO==null){
                return ObjectRestResponse.error(ErrorCode.USER_NOT_EXIST.value(),ErrorCode.USER_NOT_EXIST.message());
            }
            token = loginManager.createToken(userDetailsDTO, params.get(SYSTEM_CODE_KEY));
            String cacheKey = params.get(CasConstants.SYSTEM_CODE_KEY) + userDetailsDTO.getUserId();
            redisUserCache.putTokenInCache(cacheKey, token);
            //开启记录日志
            if(Boolean.valueOf(env.getProperty("userLoginLog.enabled"))){
                //=======================================临时记录非苏州登录日志=======================================
                //登录成功，此时记录登录成功日志
                //记录ip
                HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
                String loginIp = IpUtils.getIpAddress(request);
                UserLog userSuccessLog = UserLog.builder().baseUserId(userDetailsDTO.getUserId())
                        .loginType(Optional.ofNullable(userInfo.getLoginType()).orElse(LoginConstants.LoginType.ACCOUNT_PASSWORD.getCode()))
                        .accountType("domain".equals(userInfo.getType()) ? LoginConstants.AccountType.DOMAIN_ACCOUNT.getCode() : LoginConstants.AccountType.NORMAL_ACCOUNT.getCode())
                        .equipmentType(Optional.ofNullable(userInfo.getEquipmentType()).orElse(LoginConstants.EquipmentType.WEBPAGE.getCode()))
                        .loginResult(LoginConstants.LoginResult.SUCCESS.getCode())
                        .loginIp(loginIp)
                        .build();
                loginManager.insertUserLog(userSuccessLog);
                //===================================================================================================
            }
        }
        if(StringUtils.isNotBlank(token)){
            log.info(token);
            tokenEntity.setToken(token);

            log.info("-------");
            return new ObjectRestResponse<>().data(tokenEntity);
        }else {
            return ObjectRestResponse.error(ErrorCode.USER_INVALID.value(),ErrorCode.USER_INVALID.message());
        }
    }


    @RequestMapping("/login/refresh")
    public BaseResponse refreshToken(@RequestParam String oldToken,@RequestParam String ua) throws Exception {
        CheckParametersUtil.getInstance()
                .put(oldToken,"oldToken")
                .put(ua,"ua")
                .checkParameter();
        /**
         * 旧token进来 判断是不是redis里最后登录token
         * 是 --》 查数据库信息 生成新 token 放入redis 数据库 返回
         * 不是返回错误信息
         */
        String userId ="";
        String buId ="";
        List<Roles> roles=new ArrayList<>();
        Map<String,Object> map=new HashMap<>();
//        map=jdbcTemplete.queryCacheToken(oldToken);
        try{
        IJWTInfo info= jwtTokenUtil.getInfoFromToken(oldToken);
        userId=info.getId();
        buId=info.getBureauId();
        roles =info.getRoles();
        } catch (ExpiredJwtException e){
           Claims claims= e.getClaims();
           userId= Optional.ofNullable(claims.get("id")).orElse(StringUtils.EMPTY).toString();
           buId= Optional.ofNullable(claims.get("bureauId")).orElse(StringUtils.EMPTY).toString();
           roles= new ArrayList<>((List<Roles>)claims.get("roles"));
        }
        String redisToken= redisUserCache.getTokenFromCache(ua+userId);
        if(oldToken.equals(redisToken)){
            JWTInfoForCas jwtInfoForCas = new JWTInfoForCas(null, userId, null, ua, roles, buId);
            String newToken= jwtTokenUtil.generateToken(jwtInfoForCas);
            redisUserCache.putTokenInCache(ua+userId,newToken);
//            jdbcTemplete.insertToken(newToken,userId,buId);
            log.info("id---"+userId+"-----------refresh token");
            log.info(newToken);
            tokenEntity.setToken(newToken);
            //当刷新token的时候，添加一条日志记录（除了登录时间外，其余属性全和最近一次登录保持一致？）


            return  new ObjectRestResponse<>().data(tokenEntity);
        } else{
            return ObjectRestResponse.error(ErrorCode.USER_TOKEN_EXPIRED);
        }
    }

    @GetMapping("/user/{username}")
    public ObjectRestResponse loadUserByName(@PathVariable String username) {
        return ObjectRestResponse.ok("token", "token");
    }

    @GetMapping("/login/ds/{teacherId}")
    public ObjectRestResponse testDs(@PathVariable String teacherId) {
        return ObjectRestResponse.ok(mysqlConfig.testDynamicDatasource(teacherId));
    }

}
